<?php


/**
 * 外观（门面）模式
 * 
 * 概述：为子系统中的一组接口提供一个一致的界面，Facade模式定义了一个高层次的接口，使得子系统更加容易使用
 * 
 * 类型：结构型模式
 * 
 * 角色：
 *  1，外观角色。被客户端调用。知道相关的子系统的功能和责任。将用户的请求指派给适当的子系统处理。
 *  2，子系统角色。实现子系统的功能；每一个子系统都可以被客户端直接调用，或者被外观角色调用，
 *     它处理由外观类传过来的请求；子系统并不知道外观的存在，对于子系统而言，外观角色仅仅是另外一个客户端而已。
 * 
 * 优点：
 *  1，对客户端屏蔽了子系统组件，减少了客户端所需处理的对象数目并使得子系统使用起来更加容易；
 *  2，实现了子系统与客户端之间的松耦合关系，这使得子系统的变化不会影响到调用它的客户端，只需要调整外观类即可；
 *  3，一个子系统的修改对其他子系统没有任何影响，而且子系统内部变化也不会影响到外观对象。
 * 
 * 缺点：
 *  1，增加、删除或更换与外观类交互的子系统类，必须修改外观类或客户端的源代码，违背开闭原则
 * 
 * 适用场景：
 *  1，当要为访问一系列复杂的子系统提供一个简单入口时可以使用外观模式。
 *  2，客户端程序与多个子系统之间存在很大的依赖性。引入外观类可以将子系统与客户端解耦，
 *     从而提高子系统的独立性和可移植性。
 *  3，在层次化结构中，可以使用外观模式定义系统中每一层的入口，层与层之间不直接产生联系，
 *     而通过外观类建立联系，降低层之间的耦合度。
 * 
 * 其它：
 *  1，抽象外观类。系统具有良好的扩展性，符合开闭原则。
 *  2，外观类的单列化。由于外观类维持了对多个子系统类的引用，外观对象在系统运行时将占用较多的系统资源，
 *     因此需要对外观对象的数量进行限制，避免系统资源的浪费。
 */

/**
 * 子系统角色
 */
class SubsystemA
{
	public function method1() {
		echo 'SubsystemA method1被调用。<br/>';
	}
	
	public function method2() {
		echo 'SubsystemA method2被调用。<br/>';
	}
}
/**
 * 子系统角色
 */
class SubsystemB
{
	public function method1() {
		echo 'SubsystemB method1被调用。<br/>';
	}
	
	public function method2() {
		echo 'SubsystemB method2被调用。<br/>';
	}
}
/**
 * 子系统角色
 */
class SubsystemC
{
	public function method1() {
		echo 'SubsystemC method1被调用。<br/>';
	}
	
	public function method2() {
		echo 'SubsystemC method2被调用。<br/>';
	}
}
/**
 * 外观角色
 */
class Facade
{
	private $_subsystemA;
	private $_subsystemB;
	private $_subsystemC;
	
	public function __construct() {
		$this->_subsystemA = new SubsystemA();
		$this->_subsystemB = new SubsystemB();
		$this->_subsystemC = new SubsystemC();		
	}
	
	public function method1()
	{
		$this->_subsystemA->method1();
		$this->_subsystemB->method1();
	}
	
	public function method2()
	{
		$this->_subsystemA->method2();
		$this->_subsystemB->method2();
		$this->_subsystemC->method2();
	}
}

class Client
{
	public static function main() {
		$facade = new Facade();
		echo '调用Facade->method1()：<br/>';
		$facade->method1();
		echo '-----------------------------<br/>';
		echo '调用Facade->method2()：<br/>';
		$facade->method2();
	}
}
 
Client::main();